Conversation
The continuity stage validated its candidate with candidate.valid(1e-5), which re-evaluates every model row from the values CBC wrote to its solution file. CBC prints eight significant digits, so a 40 kWh SOC comes back rounded to 1e-3 and the balance rows miss the tolerance by up to 8e-4. The candidate was discarded on every request with a sizeable EV battery, silently, and the schedule kept its interruptions. Measured on the request from #146: the candidate found one charge start at identical cost and was thrown away because 79 rows were off. CBC already held the model rows within its own tolerance. Check only what this stage adds, the cost, preference and peak bounds, and the integrality of what came back. A test with a 40 kWh battery pins it; the existing cases stay below 10 kWh, where eight digits are still enough. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Five solver runs share one clock and the constants that size them sit across three modules. One table in the README names each stage, when it runs, and the setting or constant that bounds it, next to the log fields that report it. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The table already says when the pass runs and what bounds it. The one sentence the section added, that this is a preference and not a guarantee, moves into its row. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…testing) Squashed application of the upstream 'feat/fewer-charging-interruptions' branch (as of e016fe7) on top of our dev, for local evaluation. Not our own feature — revert this commit if it doesn't hold up or once the upstream PR lands and we do a real merge instead. Adds a fifth solve stage after the tie-break: for batteries with c_min > 0 and a fragmented schedule, minimize charge starts under strict bounds on the achieved cost, preference objective, and each leveled grid peak, so fewer interruptions never trade away money, existing preferences, or peak shaping. Bounded to 1s of solver time within the remaining request budget. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HMJZPAoqmpKJEVnPNApipb
|
Like it. This reduces breaks and helps a lot. I even could imagine to have a small cost factor applied which would not be that wrong but is difficult to define. Happy with the current idea. |
|
Looks like it would solve the issues in my last two auto-mode planner test runs: evcc-io/evcc#33763 (comment) |
|
Here the 5-min snapshots from optimizer during my last charging session. It shows the jumping scheduled charging slots between solves. evopt-history.zip I used the cloud instance that should have this fix preview-deployed already (@andig). So it does not seem to work as intended yet. |
|
There is a chance that equal costs is not true hence the tie break is not applied. Needs to check the logs in detail to be sure because of that. |
|
It seems this is not about interruptions but about influencing an equal-cost solve into a particular direction so they remain stable across solves? Which direction would that be and how would be formulate this mathematically? |
|
I analyzed the 108 snapshots from Setup in the data
What is stable, what jumpsThe block that actually controls charging is stable for four hours of solves: What jumps is:
Cause 1 — the car/home-battery split is degenerateTwo plan families alternate across solves:
Grid export is zero in 100 of 108 solves, so the whole PV surplus is absorbed either way. Total stored energy, grid import and grid export are identical between the families — only the split between car and home battery differs. Since Objective values confirm this. Within each quarter-hour the objective is linear in
Same within ±0.002, with no systematic ordering. The alternation is not one solve finding a better plan — both plans are optimal, and which one comes back is arbitrary. Cause 2 — price plateausAll slots 00:00–05:00 carry one price, so any placement of the remaining energy inside that window costs exactly the same. The same holds after 05:00 (all 0.3133 €/kWh), which is why the last 1.5 kWh floats between The inputs do not explain the jumpingI compared consecutive requests on their shared timestamp grid. 59 consecutive pairs have byte-identical
So the change originates inside the solve (branching order, incumbent at the cutoff), not in the data. Effect on the real charging sessionCommanded slot-0 power for the car, while it still needed energy:
Full stops are commanded at 03:26, 04:40, 05:02, 05:07, 05:12 and 05:23 — that matches the interruptions you observed. Why the tie-break in this PR does not bite hereFamily A has fewer car blocks than family B (2 versus 3 over the whole horizon), yet family B is returned in roughly 40 of the solves. Two things are visible in the data:
A within-solve tie-break alone cannot stabilize this. What the data suggests is needed:
Side findingThe solve at 🤖 Generated with Claude Code |
You loose either way. |
The continuity stage assumed every device enters the horizon switched off, so keeping a running session on scored the same as stopping it and restarting one slot later. A device reporting c_initial above zero now enters the horizon on: continuing costs no start, interrupting costs one, and a plan that only moves the start earlier is worth polishing.
Only the on/off state decides a charge start, so c_active says that directly instead of making the model derive it from a power value it never uses.
|
To anchor a solve seems appropriate to me as well. We've had quite comparable situations by the continuous planner if I remember it correct. |
feat: anchor charge continuity on the running session
Refs #150
Prefer fewer charging interruptions when the achieved economics and existing strategy objectives can be preserved. This is a cost-neutral preference, not enforcement of evcc's Continuous setting or a guarantee of one session when interrupted charging is cheaper.
cc @ekkea
🤖 Generated with OpenCode